/******************************************************************************

  Copyright (C), 2012-2016, ZHANGYA

 ******************************************************************************
  File Name     : windows.c
  Version       : Initial Draft
  Author        : zhangya
  Created       : 2024/5/10
  Last Modified :
  Description   : windows.c
  Function List :
  History       :
  1.Date        : 2024/5/10
    Author      : zhangya
    Modification: Created file

******************************************************************************/
#include "windows.h"
#include "lcd.h"
#include "ugui.h"
#include "logo.h"

#if 0
/*
				Menu
		Red gain:	64		(0-255)
  	  Green gain:	64		(0-255)
  	   Blue gain:	64		(0-255)
  	  Saturation:	128		(0-255)
  	  Brightness:	0		(-128-127)
  	    Contrast:	128		(0-255)
  	    	 Hue:	0		(-128-127)
  	   Sharpness:	80		(0-255)
  	     Denoise:	160		(0-255)
  	    	Edge:	120		(0-700)
  	       Input:	HDMI	(HDMI,SDI,LVDS)
  	  Information		Exit

	Menu->Information
		 App: V1.0.1
	Firmware: nucleo....
	
 */
#endif

/*--------------------------------------------------------------------*
 * $external variables                           *
 *--------------------------------------------------------------------*/
#define WIN_TITLE_FCOLOR				(C_WHITE)
#define WIN_TITLE_BCOLOR				(C_RED)

#define WIN_BCOLOR						(C_LIGHT_GRAY)

#define SET_ITEM_FCOLOR					(C_WHITE)
#define SET_ITEM_BCOLOR					(C_GOLD)

#define SELECT_ITEM_FCOLOR				(C_WHITE)
#define SELECT_ITEM_BCOLOR				(C_BLACK)

#define NO_SELECT_ITEM_FCOLOR			(C_BLACK)
#define NO_SELECT_ITEM_BCOLOR			(WIN_BCOLOR)

#define BTN_NOT_SEL_BCOLOR				(C_WHITE)
#define BTN_SEL_BCOLOR					(C_YELLOW_GREEN)

#define WIN_GUI_TIMEOUT					(30)
#define WIN_SELECT_TIME					(1000/WIN_GUI_TIMEOUT)

/*--------------------------------------------------------------------*
 * $external routine prototypes                  *
 *--------------------------------------------------------------------*/
typedef struct win_para_s{
	const char * name;
	void * txb;
	UG_U8 id;
	UG_S16 xs;
	UG_S16 ys;
}win_para_t;

typedef enum menu_num{
	MENU_MAIN,
	MENU_RED_GAIN,
	MENU_GREEN_GAIN,
	MENU_BLUE_GAIN,
	MENU_SATURATION,
	MENU_BRIGHTNESS,
	MENU_CONTRAST,
	MENU_DENOISE,
	MENU_EDGE,
	MENU_INPUT,
	MENU_INFORMATION,
	MENU_FACTORY,
	MENU_EXIT,
	SUB_MENU_INFOR,
	SUB_MENU_FACTORY
}menu_num_e;
/*--------------------------------------------------------------------*
 * $internal routine prototypes                  *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $project-wide global variables                *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $module-wide global variables                 *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $constants                                    *
 *--------------------------------------------------------------------*/
static uint16_t 	m_menu_index;
static uint16_t     m_sud_menu_index;
static UG_GUI 		m_gui;
static win_fun_t 	m_win_fun;
static bool 		m_value_flag;

/*--------------------------------------------------------------------*
 * $macros                                       *
 *--------------------------------------------------------------------*/
static void win_main_update(void);
static void win_menu1_update(void);
static void win_menu2_update(void);
static void win_sub_info_update(void);

/*--------------------------------------------------------------------*
 * $routines' implementations                    *
 *--------------------------------------------------------------------*/

/*===============================================================================
 ==============  MAIN
 */

#define MAIN_STR_BUF_LEN			(8)

static char main_hue_str[MAIN_STR_BUF_LEN];

/*****************************************************************************
 Prototype    : win_main_init
 Description  : main windows init
 Input        : void  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void win_main_init(void)
{
	lcd_show_image((const uint16_t *)gImage_logo);
}

/*****************************************************************************
 Prototype    : win_main_update
 Description  : main windown update
 Input        : void  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void win_main_update(void)
{
	int32_t value = m_win_fun.get_value(DATA_EDGE);
	snprintf(main_hue_str, sizeof(main_hue_str), "%d", value);

	lcd_fill_rect(80, 80, 180, 220, 0x2104);
	if(value >= 100){
		LCD_ShowNumAscii80(95, 80, value, 3, WHITE, 0x2104);
	}else{
		LCD_ShowNumAscii80(116, 80, value, 2, WHITE, 0x2104);
	}
}

/*===============================================================================
 ==============  MENU1
 */
#define FONT_WIDTH					(12)
#define FONT_HEIGHT					(20)
#define START_X_POINT				(45)
#define START_Y_POINT				(5)
#define MENU_STR_BUF_LEN			(24)

#define OBJECTS_MENU1        		(8)

static UG_WINDOW win_menu1;
static UG_OBJECT obj_buff_wnd_menu1[OBJECTS_MENU1];

static UG_TEXTBOX tb_red;
static UG_TEXTBOX tb_green;
static UG_TEXTBOX tb_blue;
static UG_TEXTBOX tb_saturat;
static UG_TEXTBOX tb_bright;
static UG_TEXTBOX tb_contrast;
static UG_TEXTBOX tb_denoise;
static UG_TEXTBOX tb_edge;

static char menu1_red_str[MENU_STR_BUF_LEN];
static char menu1_green_str[MENU_STR_BUF_LEN];
static char menu1_blue_str[MENU_STR_BUF_LEN];
static char menu1_saturat_str[MENU_STR_BUF_LEN];
static char menu1_bright_str[MENU_STR_BUF_LEN];
static char menu1_contrast_str[MENU_STR_BUF_LEN];
static char menu1_denoise_str[MENU_STR_BUF_LEN];
static char menu1_edge_str[MENU_STR_BUF_LEN];

const static win_para_t m_win_menu1[] = {
	{"  Red gain: %-4d", &tb_red, 		TXB_ID_0, START_X_POINT,  (START_Y_POINT * 1)},
	{"Green gain: %-4d", &tb_green,  	TXB_ID_1, START_X_POINT,  (START_Y_POINT * 2) + (FONT_HEIGHT * 1)},
	{" Blue gain: %-4d", &tb_blue,   	TXB_ID_2, START_X_POINT,  (START_Y_POINT * 3) + (FONT_HEIGHT * 2)},
	{"Saturation: %-4d", &tb_saturat,	TXB_ID_3, START_X_POINT,  (START_Y_POINT * 4) + (FONT_HEIGHT * 3)},
	{"Brightness: %-4d", &tb_bright, 	TXB_ID_4, START_X_POINT,  (START_Y_POINT * 5) + (FONT_HEIGHT * 4)},
	{"  Contrast: %-4d", &tb_contrast,	TXB_ID_5, START_X_POINT,  (START_Y_POINT * 6) + (FONT_HEIGHT * 5)},
	{"   Denoise: %-4d", &tb_denoise, 	TXB_ID_6, START_X_POINT,  (START_Y_POINT * 7) + (FONT_HEIGHT * 6)},
	{"      Edge: %-4d", &tb_edge, 		TXB_ID_7, START_X_POINT,  (START_Y_POINT * 8) + (FONT_HEIGHT * 7)},
	{NULL, NULL, 0xFF, -1, -1}
};

/*****************************************************************************
 Prototype    : win_menu1_init
 Description  : menu1 windows init
 Input        : void  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void win_menu1_init(void)
{
	UG_WindowCreate(&win_menu1, obj_buff_wnd_menu1, OBJECTS_MENU1, NULL);
	UG_WindowSetStyle(&win_menu1, WND_STYLE_3D | WND_STYLE_SHOW_TITLE);
	UG_WindowSetBackColor(&win_menu1, WIN_BCOLOR);
	UG_WindowSetTitleText(&win_menu1, "Menu 1(2)");
	UG_WindowSetTitleTextFont(&win_menu1, &FONT_10X16);
	UG_WindowSetTitleTextHSpace(&win_menu1, 0);
	UG_WindowSetTitleTextVSpace(&win_menu1, 0);
	UG_WindowSetTitleColor(&win_menu1, WIN_TITLE_BCOLOR);
	UG_WindowSetTitleTextColor(&win_menu1, WIN_TITLE_FCOLOR);
	UG_WindowSetTitleTextAlignment(&win_menu1, ALIGN_BOTTOM_CENTER);

	int index = 0;
	while (m_win_menu1[index].name != NULL) {
		UG_U8 id  = m_win_menu1[index].id;
		UG_S16 xs = m_win_menu1[index].xs;
		UG_S16 ys = m_win_menu1[index].ys;
		UG_S16 xe = xs + UG_WindowGetInnerWidth(&win_menu1) - 2 * START_X_POINT;
		UG_S16 ye = ys + FONT_HEIGHT;
		UG_TextboxCreate(&win_menu1, m_win_menu1[index].txb, id, xs, ys, xe, ye);
		UG_TextboxSetFont(&win_menu1, id, &FONT_12X20);
		UG_TextboxSetText(&win_menu1, id, (char *)m_win_menu1[index].name);
		UG_TextboxSetHSpace(&win_menu1, id, 0);
		UG_TextboxSetVSpace(&win_menu1, id, 0);
		UG_TextboxSetAlignment(&win_menu1, id, ALIGN_CENTER);
		index++;
	}
	win_menu1_update();
	UG_WindowHide(&win_menu1);
}

/*****************************************************************************
 Prototype    : win_menu1_update
 Description  : menu1 windows update
 Input        : void  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void win_menu1_update(void)
{
	int32_t value = m_win_fun.get_value(DATA_RED_GAIN);
	snprintf(menu1_red_str, sizeof(menu1_red_str), m_win_menu1[0].name, value);
	UG_TextboxSetText(&win_menu1, TXB_ID_0, menu1_red_str);

	value = m_win_fun.get_value(DATA_GREEN_GAIN);
	snprintf(menu1_green_str, sizeof(menu1_green_str), m_win_menu1[1].name, value);
	UG_TextboxSetText(&win_menu1, TXB_ID_1, menu1_green_str);

	value = m_win_fun.get_value(DATA_BLUE_GAIN);
	snprintf(menu1_blue_str, sizeof(menu1_blue_str), m_win_menu1[2].name, value);
	UG_TextboxSetText(&win_menu1, TXB_ID_2, menu1_blue_str);

	value = m_win_fun.get_value(DATA_SATURATION);
	snprintf(menu1_saturat_str, sizeof(menu1_saturat_str), m_win_menu1[3].name, value);
	UG_TextboxSetText(&win_menu1, TXB_ID_3, menu1_saturat_str);

	value = m_win_fun.get_value(DATA_BRIGHTNESS);
	snprintf(menu1_bright_str, sizeof(menu1_bright_str), m_win_menu1[4].name, value);
	UG_TextboxSetText(&win_menu1, TXB_ID_4, menu1_bright_str);

	value = m_win_fun.get_value(DATA_CONTRAST);
	snprintf(menu1_contrast_str, sizeof(menu1_contrast_str), m_win_menu1[5].name, value);
	UG_TextboxSetText(&win_menu1, TXB_ID_5, menu1_contrast_str);

	value = m_win_fun.get_value(DATA_DENOISE);
	snprintf(menu1_denoise_str, sizeof(menu1_denoise_str), m_win_menu1[6].name, value);
	UG_TextboxSetText(&win_menu1, TXB_ID_6, menu1_denoise_str);

	value = m_win_fun.get_value(DATA_EDGE);
	snprintf(menu1_edge_str, sizeof(menu1_edge_str), m_win_menu1[7].name, value);
	UG_TextboxSetText(&win_menu1, TXB_ID_7, menu1_edge_str);
}

/*===============================================================================
 ==============  MENU2
 */
#define OBJECTS_MENU2        		(4)

static UG_WINDOW win_menu2;
static UG_OBJECT obj_buff_wnd_menu2[OBJECTS_MENU2];

static UG_TEXTBOX tb_input;
static UG_TEXTBOX tb_infor;
static UG_TEXTBOX tb_factory;
static UG_TEXTBOX tb_exit;

static char menu2_input_str[MENU_STR_BUF_LEN];

const static win_para_t m_win_menu2[] = {
	{"  Input:  %-4s", 	&tb_input, 		TXB_ID_0, START_X_POINT,  (START_Y_POINT * 1)},
	{"Information", 	&tb_infor,		TXB_ID_1, START_X_POINT,  (START_Y_POINT * 2) + (FONT_HEIGHT * 1)},
	{"Factory reset", 	&tb_factory,	TXB_ID_2, START_X_POINT,  (START_Y_POINT * 3) + (FONT_HEIGHT * 2)},
	{"Exit",  			&tb_exit,		TXB_ID_3, START_X_POINT,  (START_Y_POINT * 4) + (FONT_HEIGHT * 3)},
	{NULL, NULL, 0xFF, -1, -1}
};

/*****************************************************************************
 Prototype    : win_menu2_init
 Description  : menu2 windows init
 Input        : void  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void win_menu2_init(void)
{
	UG_WindowCreate(&win_menu2, obj_buff_wnd_menu2, OBJECTS_MENU2, NULL);
	UG_WindowSetStyle(&win_menu2, WND_STYLE_3D | WND_STYLE_SHOW_TITLE);
	UG_WindowSetBackColor(&win_menu2, WIN_BCOLOR);
	UG_WindowSetTitleText(&win_menu2, "Menu 2(2)");
	UG_WindowSetTitleTextFont(&win_menu2, &FONT_10X16);
	UG_WindowSetTitleTextHSpace(&win_menu2, 0);
	UG_WindowSetTitleTextVSpace(&win_menu2, 0);
	UG_WindowSetTitleColor(&win_menu2, WIN_TITLE_BCOLOR);
	UG_WindowSetTitleTextColor(&win_menu2, WIN_TITLE_FCOLOR);
	UG_WindowSetTitleTextAlignment(&win_menu2, ALIGN_BOTTOM_CENTER);

	int index = 0;
	while (m_win_menu2[index].name != NULL)
	{
		UG_U8 id  = m_win_menu2[index].id;
		UG_S16 xs = m_win_menu2[index].xs;
		UG_S16 ys = m_win_menu2[index].ys;
		UG_S16 xe = xs + UG_WindowGetInnerWidth(&win_menu2) - 2 * START_X_POINT;
		UG_S16 ye = ys + FONT_HEIGHT;
		UG_TextboxCreate(&win_menu2, m_win_menu2[index].txb, id, xs, ys, xe, ye);
		UG_TextboxSetFont(&win_menu2, id, &FONT_12X20);
		UG_TextboxSetText(&win_menu2, id, (char *)m_win_menu2[index].name);
		UG_TextboxSetHSpace(&win_menu2, id, 0);
		UG_TextboxSetVSpace(&win_menu2, id, 0);
		UG_TextboxSetAlignment(&win_menu2, id, ALIGN_CENTER);
		index++;
	}
	win_menu2_update();

	UG_WindowHide(&win_menu2);
}

/*****************************************************************************
 Prototype    : win_menu2_update
 Description  : menu2 windows update
 Input        : void  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void win_menu2_update(void)
{
	char * str = m_win_fun.get_str(DATA_INPUT);
	snprintf(menu2_input_str, sizeof(menu2_input_str), m_win_menu2[0].name, str);
	UG_TextboxSetText(&win_menu2, TXB_ID_0, menu2_input_str);
}

/*===============================================================================
 ==============  SUB MENU
 */
#undef START_X_POINT
#define START_X_POINT					(5)
#define SUB_INFO_VER_LEN				(56)

#define OBJECTS_SUB_INFO        		(3)

static UG_WINDOW win_sub_info;
static UG_OBJECT obj_buff_wnd_sub_info[OBJECTS_SUB_INFO];

static UG_TEXTBOX tb_app_ver;
static UG_TEXTBOX tb_mcu_ver;
static UG_TEXTBOX tb_fpga_ver;

static char sub_app_ver_str[SUB_INFO_VER_LEN];
static char sub_mcu_ver_str[SUB_INFO_VER_LEN];
static char sub_fpga_ver_str[SUB_INFO_VER_LEN];

const static win_para_t m_win_sub_info[] = {
	{" APP: %s", &tb_app_ver,	TXB_ID_0, START_X_POINT,  (START_Y_POINT * 1)	},
	{" MCU: %s", &tb_mcu_ver, 	TXB_ID_1, START_X_POINT,  (START_Y_POINT * 2) + (FONT_HEIGHT * 1)},
	{"FPGA: %s", &tb_fpga_ver, 	TXB_ID_2, START_X_POINT,  (START_Y_POINT * 3) + (FONT_HEIGHT * 2)},
	{NULL, NULL, 0xFF, -1, -1}
};

/*****************************************************************************
 Prototype    : win_sub_info_init
 Description  : sub windows infor init
 Input        : void  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void win_sub_info_init(void)
{
	UG_WindowCreate(&win_sub_info, obj_buff_wnd_sub_info, OBJECTS_SUB_INFO, NULL);
	UG_WindowSetStyle(&win_sub_info, WND_STYLE_3D | WND_STYLE_SHOW_TITLE);
	UG_WindowSetBackColor(&win_sub_info, WIN_BCOLOR);
	UG_WindowSetTitleText(&win_sub_info, "Menu->Infor");
	UG_WindowSetTitleTextFont(&win_sub_info, &FONT_10X16);
	UG_WindowSetTitleTextHSpace(&win_sub_info, 0);
	UG_WindowSetTitleTextVSpace(&win_sub_info, 0);
	UG_WindowSetTitleColor(&win_sub_info, WIN_TITLE_BCOLOR);
	UG_WindowSetTitleTextColor(&win_sub_info, WIN_TITLE_FCOLOR);
	UG_WindowSetTitleTextAlignment(&win_sub_info, ALIGN_BOTTOM_LEFT);

	int index = 0;
	while (m_win_sub_info[index].name != NULL)
	{
		UG_U8 id  = m_win_sub_info[index].id;
		UG_S16 xs = m_win_sub_info[index].xs;
		UG_S16 ys = m_win_sub_info[index].ys;
		UG_S16 xe = xs + UG_WindowGetInnerWidth(&win_sub_info) - 2 * START_X_POINT;
		UG_S16 ye = ys + FONT_HEIGHT;
		UG_TextboxCreate(&win_sub_info, m_win_sub_info[index].txb, id, xs, ys, xe, ye);
		UG_TextboxSetFont(&win_sub_info, id, &FONT_12X20);
		UG_TextboxSetText(&win_sub_info, id, (char *)m_win_sub_info[index].name);
		UG_TextboxSetHSpace(&win_sub_info, id, 0);
		UG_TextboxSetVSpace(&win_sub_info, id, 0);
		UG_TextboxSetAlignment(&win_sub_info, id, ALIGN_CENTER_LEFT);
		index++;
	}
	win_sub_info_update();
	UG_WindowHide(&win_sub_info);
}

/*****************************************************************************
 Prototype    : win_sub_info_update
 Description  : sub window infor update
 Input        : void  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void win_sub_info_update(void)
{
	char * str = m_win_fun.get_str(DATA_APP_VER);
	if (strlen(str) > 0)
	{
		snprintf(sub_app_ver_str, sizeof(sub_app_ver_str), m_win_sub_info[0].name, str);
		UG_TextboxSetText(&win_sub_info, TXB_ID_0, sub_app_ver_str);
	}

	str = m_win_fun.get_str(DATA_FPGA_VER);
	//nucleo: 2.1.5689 build 2024-05-15 17:51:00 +0800 CST GCC: 13.2.1 20231009 FPGA: 2024425A
	if (strlen(str) > 0)
	{
		int is, ie;

		is = strlen("nucleo: ");
		ie = strstr((const char *)str, " build") - (char *)str;
		DEBUG_INFO("is=%d,ie=%d\r\n", is, ie);
		memset(sub_mcu_ver_str, 0, sizeof(sub_mcu_ver_str));
		memcpy(&(sub_mcu_ver_str[SUB_INFO_VER_LEN/2]), &(str[is]), ie - is);
		snprintf(sub_mcu_ver_str, sizeof(sub_mcu_ver_str), m_win_sub_info[1].name, 
			&(sub_mcu_ver_str[SUB_INFO_VER_LEN/2]));

		is = strstr((const char *)str, "FPGA: ") - (char *)str;
		is += strlen("FPGA: ");
		memset(sub_fpga_ver_str, 0, sizeof(sub_fpga_ver_str));
		memcpy(&sub_fpga_ver_str[SUB_INFO_VER_LEN/2], &(str[is]), strlen(str) - is);
		snprintf(sub_fpga_ver_str, sizeof(sub_fpga_ver_str), m_win_sub_info[2].name, 
			&(sub_fpga_ver_str[SUB_INFO_VER_LEN/2]));

		UG_TextboxSetText(&win_sub_info, TXB_ID_1, sub_mcu_ver_str);
		UG_TextboxSetText(&win_sub_info, TXB_ID_2, sub_fpga_ver_str);
	}else{
		snprintf(sub_mcu_ver_str, sizeof(sub_fpga_ver_str), m_win_sub_info[2].name, "Empty data");
		snprintf(sub_fpga_ver_str, sizeof(sub_fpga_ver_str), m_win_sub_info[2].name, "Empty data");
		UG_TextboxSetText(&win_sub_info, TXB_ID_1, sub_mcu_ver_str);
		UG_TextboxSetText(&win_sub_info, TXB_ID_2, sub_fpga_ver_str);
	}
}

/*===============================================================================
 ==============   TIPS
 */
#define BTN_X_SIZE						(90)
#define BTN_Y_SIZE						(30)
#define BTN_FLASH_DLY					(40)
#define FACTORY_SET_TIME				(20)

#define TIPS_STR_LEN					(56)
#define OBJECTS_TIPS_INFO        		(3)

static UG_WINDOW win_tips;
static UG_OBJECT obj_buff_wnd_tips[OBJECTS_TIPS_INFO];

static UG_TEXTBOX 	tb_tips;
static UG_BUTTON 	btn_cancel;
static UG_BUTTON 	btn_confirm;

static char win_tips_str[TIPS_STR_LEN];

static int btn_flash_cnt 	= -1;
static int factory_set_dly 	= -1;

static void win_tips_init(void)
{
	int xs = 40;
	int ys = 50;
	int xe = UG_GetXDim() - xs;
	int ye = UG_GetYDim() - ys;
	UG_WindowCreate(&win_tips, obj_buff_wnd_tips, OBJECTS_TIPS_INFO, NULL);
	UG_WindowSetStyle(&win_tips, WND_STYLE_3D | WND_STYLE_SHOW_TITLE);
	UG_WindowResize(&win_tips, xs, ys, xe, ye);
	UG_WindowSetBackColor(&win_tips, WIN_BCOLOR);
	UG_WindowSetTitleText(&win_tips, "Menu->Factory");
	UG_WindowSetTitleTextFont(&win_tips, &FONT_10X16);
	UG_WindowSetTitleTextHSpace(&win_tips, 0);
	UG_WindowSetTitleTextVSpace(&win_tips, 0);
	UG_WindowSetTitleColor(&win_tips, WIN_TITLE_BCOLOR);
	UG_WindowSetTitleTextColor(&win_tips, WIN_TITLE_FCOLOR);
	UG_WindowSetTitleTextAlignment(&win_tips, ALIGN_BOTTOM_LEFT);

	UG_TextboxCreate(&win_tips, &tb_tips, TXB_ID_0, 0, 0, 
		UG_WindowGetInnerWidth(&win_tips), 
		UG_WindowGetInnerHeight(&win_tips) - BTN_Y_SIZE - 6);
	UG_TextboxSetFont(&win_tips, TXB_ID_0, &FONT_12X20);
	UG_TextboxSetText(&win_tips, TXB_ID_0, (char *)win_tips_str);
	UG_TextboxSetHSpace(&win_tips, TXB_ID_0, 0);
	UG_TextboxSetVSpace(&win_tips, TXB_ID_0, 0);
	UG_TextboxSetAlignment(&win_tips, TXB_ID_0, ALIGN_CENTER);

	xs = 15;
	ys = UG_WindowGetInnerHeight(&win_tips) - BTN_Y_SIZE - 5;
	xe = xs + BTN_X_SIZE;
	ye = ys + BTN_Y_SIZE;
	UG_ButtonCreate(&win_tips, &btn_cancel, BTN_ID_0, xs, ys, xe, ye);
	UG_ButtonSetFont(&win_tips, BTN_ID_0, &FONT_10X16);
    UG_ButtonSetBackColor(&win_tips, BTN_ID_0, BTN_NOT_SEL_BCOLOR);
    UG_ButtonSetText(&win_tips, BTN_ID_0, "Cancel");

	xs = UG_WindowGetInnerWidth(&win_tips) - 15 - BTN_X_SIZE;
	ys = UG_WindowGetInnerHeight(&win_tips) - BTN_Y_SIZE - 5;
	xe = xs + BTN_X_SIZE;
	ye = ys + BTN_Y_SIZE;
	UG_ButtonCreate(&win_tips, &btn_confirm, BTN_ID_1, xs, ys, xe, ye);
	UG_ButtonSetFont(&win_tips, BTN_ID_1, &FONT_10X16);
    UG_ButtonSetBackColor(&win_tips, BTN_ID_1, BTN_NOT_SEL_BCOLOR);
    UG_ButtonSetText(&win_tips, BTN_ID_1, "Confirm");

	win_tips_update("Factory reset");
	UG_WindowHide(&win_tips);
}

void win_tips_update(const char * str)
{
	if (str == NULL) {
		DEBUG_STR("tips str is null\r\n");
		return ;
	}
	int len = strlen(str);
	if (len > TIPS_STR_LEN)
		len = TIPS_STR_LEN - 1;
	memset(win_tips_str, 0, TIPS_STR_LEN);
	memcpy(win_tips_str, str, len);
	UG_TextboxSetText(&win_tips, TXB_ID_0, win_tips_str);
}

/*===============================================================================
 ==============  menu select
 */
typedef struct menu_select_s{
	UG_WINDOW * win;
	UG_U8 id;
}menu_select_t;

static const menu_select_t m_menu_select_list[] = {
	{NULL, 0xff},	//main
	{&win_menu1, 	TXB_ID_0},
	{&win_menu1, 	TXB_ID_1},
	{&win_menu1, 	TXB_ID_2},
	{&win_menu1, 	TXB_ID_3},
	{&win_menu1, 	TXB_ID_4},
	{&win_menu1, 	TXB_ID_5},
	{&win_menu1, 	TXB_ID_6},
	{&win_menu1, 	TXB_ID_7},
	{&win_menu2, 	TXB_ID_0},	//input
	{&win_menu2, 	TXB_ID_1},	//information
	{&win_menu2, 	TXB_ID_2},	//factory reset
	{&win_menu2, 	TXB_ID_3},  //exit
	{NULL, 			0xFF}};

/*****************************************************************************
 Prototype    : menu_up
 Description  : menu select up
 Input        : uint16_t * index  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void menu_up(uint16_t * index)
{
	if (m_value_flag)
		return ;
	if (index == NULL)
	{
		DEBUG_STR("menu_up:index==null");
		return ;
	}
	UG_U8 id;
	UG_WINDOW * win;

	uint16_t old_index = *index;
	uint16_t new_index;
	new_index = (old_index == MENU_RED_GAIN)?(MENU_INPUT):(old_index - 1);
	
	win = m_menu_select_list[old_index].win;
	id = m_menu_select_list[old_index].id;
	UG_TextboxSetForeColor(win, id, NO_SELECT_ITEM_FCOLOR);
	UG_TextboxSetBackColor(win, id, NO_SELECT_ITEM_BCOLOR);

	win = m_menu_select_list[new_index].win;
	id = m_menu_select_list[new_index].id;
	UG_TextboxSetForeColor(win, id, SELECT_ITEM_FCOLOR);
	UG_TextboxSetBackColor(win, id, SELECT_ITEM_BCOLOR);

	if (m_menu_select_list[old_index].win != m_menu_select_list[new_index].win)
	{
		UG_WindowHide(m_menu_select_list[old_index].win);
		UG_WindowShow(m_menu_select_list[new_index].win);

		UG_TextboxSetForeColor(&win_menu2, TXB_ID_3, NO_SELECT_ITEM_FCOLOR);
		UG_TextboxSetBackColor(&win_menu2, TXB_ID_3, NO_SELECT_ITEM_BCOLOR);
	}

	*index = new_index;
}

/*****************************************************************************
 Prototype    : menu_down
 Description  : menu select down
 Input        : uint16_t * index  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void menu_down(uint16_t * index)
{
	if (m_value_flag)
		return ;
	if (index == NULL)
	{
		DEBUG_STR("menu_down:index==null");
		return ;
	}
	UG_U8 id;
	UG_WINDOW * win;

	uint16_t old_index = *index;
	uint16_t new_index;
	new_index = (old_index >= MENU_EXIT)?(MENU_RED_GAIN):(old_index + 1);
	
	win = m_menu_select_list[old_index].win;
	id = m_menu_select_list[old_index].id;
	UG_TextboxSetForeColor(win, id, NO_SELECT_ITEM_FCOLOR);
	UG_TextboxSetBackColor(win, id, NO_SELECT_ITEM_BCOLOR);

	win = m_menu_select_list[new_index].win;
	id = m_menu_select_list[new_index].id;
	UG_TextboxSetForeColor(win, id, SELECT_ITEM_FCOLOR);
	UG_TextboxSetBackColor(win, id, SELECT_ITEM_BCOLOR);

	if (m_menu_select_list[old_index].win != m_menu_select_list[new_index].win)
	{
		UG_WindowHide(m_menu_select_list[old_index].win);
		UG_WindowShow(m_menu_select_list[new_index].win);

		UG_TextboxSetForeColor(&win_menu2, TXB_ID_3, NO_SELECT_ITEM_FCOLOR);
		UG_TextboxSetBackColor(&win_menu2, TXB_ID_3, NO_SELECT_ITEM_BCOLOR);
	}

	*index = new_index;
}

/*****************************************************************************
 Prototype    : data_change
 Description  : change menu data
 Input        : uint16_t index  
                int32_t v       
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void data_change(uint16_t index, int32_t v)
{
	if (!m_value_flag)
		return ;

	int32_t value = 0;
	if (index == MENU_RED_GAIN)
	{
		value = m_win_fun.get_value(DATA_RED_GAIN);
		value += v;
		m_win_fun.set_value(DATA_RED_GAIN, value);
		value = m_win_fun.get_value(DATA_RED_GAIN);
		snprintf(menu1_red_str, sizeof(menu1_red_str), m_win_menu1[0].name, value);
		UG_TextboxSetText(&win_menu1, TXB_ID_0, menu1_red_str);
	}
	else if (index == MENU_GREEN_GAIN)
	{
		value = m_win_fun.get_value(DATA_GREEN_GAIN);
		value += v;
		m_win_fun.set_value(DATA_GREEN_GAIN, value);
		value = m_win_fun.get_value(DATA_GREEN_GAIN);
		snprintf(menu1_green_str, sizeof(menu1_green_str), m_win_menu1[1].name, value);
		UG_TextboxSetText(&win_menu1, TXB_ID_1, menu1_green_str);
	}
	else if (index == MENU_BLUE_GAIN)
	{
		value = m_win_fun.get_value(DATA_BLUE_GAIN);
		value += v;
		m_win_fun.set_value(DATA_BLUE_GAIN, value);
		value = m_win_fun.get_value(DATA_BLUE_GAIN);
		snprintf(menu1_blue_str, sizeof(menu1_blue_str), m_win_menu1[2].name, value);
		UG_TextboxSetText(&win_menu1, TXB_ID_2, menu1_blue_str);
	}
	else if (index == MENU_SATURATION)
	{
		value = m_win_fun.get_value(DATA_SATURATION);
		value += v;
		m_win_fun.set_value(DATA_SATURATION, value);
		value = m_win_fun.get_value(DATA_SATURATION);
		snprintf(menu1_saturat_str, sizeof(menu1_saturat_str), m_win_menu1[3].name, value);
		UG_TextboxSetText(&win_menu1, TXB_ID_3, menu1_saturat_str);
	}
	else if (index == MENU_BRIGHTNESS)
	{
		value = m_win_fun.get_value(DATA_BRIGHTNESS);
		value += v;
		m_win_fun.set_value(DATA_BRIGHTNESS, value);
		value = m_win_fun.get_value(DATA_BRIGHTNESS);
		snprintf(menu1_bright_str, sizeof(menu1_bright_str), m_win_menu1[4].name, value);
		UG_TextboxSetText(&win_menu1, TXB_ID_4, menu1_bright_str);
	}
	else if (index == MENU_CONTRAST)
	{
		value = m_win_fun.get_value(DATA_CONTRAST);
		value += v;
		m_win_fun.set_value(DATA_CONTRAST, value);
		value = m_win_fun.get_value(DATA_CONTRAST);
		snprintf(menu1_contrast_str, sizeof(menu1_contrast_str), m_win_menu1[5].name, value);
		UG_TextboxSetText(&win_menu1, TXB_ID_5, menu1_contrast_str);
	}
	else if (index == MENU_DENOISE)
	{
		value = m_win_fun.get_value(DATA_DENOISE);
		value += v;
		m_win_fun.set_value(DATA_DENOISE, value);
		value = m_win_fun.get_value(DATA_DENOISE);
		snprintf(menu1_denoise_str, sizeof(menu1_denoise_str), m_win_menu1[6].name, value);
		UG_TextboxSetText(&win_menu1, TXB_ID_6, menu1_denoise_str);
	}
	else if (index == MENU_EDGE)
	{
		value = m_win_fun.get_value(DATA_EDGE);
		value += v;
		m_win_fun.set_value(DATA_EDGE, value);
		value = m_win_fun.get_value(DATA_EDGE);
		snprintf(menu1_edge_str, sizeof(menu1_edge_str), m_win_menu1[7].name, value);
		UG_TextboxSetText(&win_menu1, TXB_ID_7, menu1_edge_str);
	}
	else if (index == MENU_INPUT)
	{
		value = m_win_fun.get_value(DATA_INPUT);
		value += v;
		m_win_fun.set_value(DATA_INPUT, value);
		char * str = m_win_fun.get_str(DATA_INPUT);
		snprintf(menu2_input_str, sizeof(menu2_input_str), m_win_menu2[0].name, str);
		UG_TextboxSetText(&win_menu2, TXB_ID_0, menu2_input_str);
	}
}

/*****************************************************************************
 Prototype    : win_control_menu
 Description  : control menu
 Input        : const uint16_t ctl  
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
void win_control_menu(const uint16_t ctl)
{
	if (m_win_fun.set_value == NULL || m_win_fun.get_value == NULL ||
		m_win_fun.get_str == NULL)
	{
		DEBUG_STR("win_control_menu:para is err");
		return ;
	}
	if (m_menu_index == MENU_MAIN)
	{
		if (ctl == CTL_MENU)
		{
			m_menu_index = MENU_RED_GAIN;
			UG_TextboxSetForeColor(&win_menu1, TXB_ID_0, SELECT_ITEM_FCOLOR);
			UG_TextboxSetBackColor(&win_menu1, TXB_ID_0, SELECT_ITEM_BCOLOR);
			win_menu1_update();
			win_menu2_update();
			UG_WindowShow(&win_menu1);
		}
		else if (ctl == CTL_UP || ctl == CTL_UP_LONG)
		{
			int32_t value = m_win_fun.get_value(DATA_EDGE);
			value++;
			m_win_fun.set_value(DATA_EDGE, value);
			win_main_update();
		}
		else if (ctl == CTL_DOWN || ctl == CTL_DOWN_LONG)
		{
			int32_t value = m_win_fun.get_value(DATA_EDGE);
			value--;
			m_win_fun.set_value(DATA_EDGE, value);
			win_main_update();
		}
	}
	else if (m_menu_index >= MENU_RED_GAIN && m_menu_index <= MENU_EXIT)
	{
		if (ctl == CTL_MENU)
		{
			if (m_menu_index == MENU_EXIT)
			{
				m_menu_index = MENU_MAIN;
				win_main_init();
				win_main_update();
			}
			else if (m_menu_index == MENU_INFORMATION)
			{
				m_menu_index = SUB_MENU_INFOR;
				UG_WindowHide(&win_menu2);
				win_sub_info_update();
				UG_WindowShow(&win_sub_info);
			}
			else if (m_menu_index == MENU_FACTORY)
			{
				m_menu_index = SUB_MENU_FACTORY;
				m_sud_menu_index = 0;
				btn_flash_cnt = BTN_FLASH_DLY;
				win_tips_update("Factory reset");
				UG_ButtonSetBackColor(&win_tips, BTN_ID_0, BTN_SEL_BCOLOR);
				UG_ButtonSetBackColor(&win_tips, BTN_ID_1, BTN_NOT_SEL_BCOLOR);
				UG_WindowShow(&win_tips);
			}
			else{
				UG_COLOR fcolor = SELECT_ITEM_FCOLOR;
				UG_COLOR bcolor = SELECT_ITEM_BCOLOR;
				if (m_value_flag)
				{
					fcolor = SELECT_ITEM_FCOLOR;
					bcolor = SELECT_ITEM_BCOLOR;
					m_value_flag = false;
				}else{
					fcolor = SET_ITEM_FCOLOR;
					bcolor = SET_ITEM_BCOLOR;
					m_value_flag = true;
				}
				UG_TextboxSetForeColor(m_menu_select_list[m_menu_index].win, 
								m_menu_select_list[m_menu_index].id, fcolor);
				UG_TextboxSetBackColor(m_menu_select_list[m_menu_index].win, 
								m_menu_select_list[m_menu_index].id, bcolor);
			}
		}
		else if (ctl == CTL_UP)
		{
			menu_up(&m_menu_index);
			data_change(m_menu_index, 1);
		}
		else if (ctl == CTL_DOWN)
		{
			menu_down(&m_menu_index);
			data_change(m_menu_index, -1);
		}

		if (!m_value_flag || m_menu_index > MENU_EDGE)
			return ;

		if (ctl == CTL_UP_LONG)
		{
			data_change(m_menu_index, 1);
		}
		else if (ctl == CTL_DOWN_LONG)
		{
			data_change(m_menu_index, -1);
		}
	}
	else if (m_menu_index == SUB_MENU_INFOR)
	{
		if (ctl == CTL_MENU)
		{
			m_menu_index = MENU_INFORMATION;
			UG_WindowHide(&win_sub_info);
			win_menu2_update();
			UG_WindowShow(&win_menu2);
		}
	}
	else if (m_menu_index == SUB_MENU_FACTORY)
	{
		if (ctl == CTL_MENU)
		{
			if (m_sud_menu_index == 0)
			{
				m_menu_index = MENU_FACTORY;
				btn_flash_cnt = -1;
				UG_ButtonSetBackColor(&win_tips, BTN_ID_0, BTN_NOT_SEL_BCOLOR);
				UG_ButtonSetBackColor(&win_tips, BTN_ID_1, BTN_NOT_SEL_BCOLOR);
				UG_WindowHide(&win_tips);
			}
			else if (m_sud_menu_index > 0)
			{
				btn_flash_cnt = -1;
				factory_set_dly = FACTORY_SET_TIME;
				if (m_win_fun.set_def_value)
					m_win_fun.set_def_value();
				win_update_show();
				win_tips_update("Initializing");
				UG_ButtonSetBackColor(&win_tips, BTN_ID_0, BTN_NOT_SEL_BCOLOR);
				UG_ButtonSetBackColor(&win_tips, BTN_ID_1, BTN_NOT_SEL_BCOLOR);
			}
		}
		else if (ctl == CTL_UP)
		{
			if (m_sud_menu_index)
			{
				m_sud_menu_index = 0;
				btn_flash_cnt = BTN_FLASH_DLY;
				UG_ButtonSetBackColor(&win_tips, BTN_ID_0, BTN_SEL_BCOLOR);
				UG_ButtonSetBackColor(&win_tips, BTN_ID_1, BTN_NOT_SEL_BCOLOR);
			}
		}
		else if (ctl == CTL_DOWN)
		{
			if (!m_sud_menu_index)
			{
				m_sud_menu_index = 1;
				btn_flash_cnt = BTN_FLASH_DLY;
				UG_ButtonSetBackColor(&win_tips, BTN_ID_0, BTN_NOT_SEL_BCOLOR);
				UG_ButtonSetBackColor(&win_tips, BTN_ID_1, BTN_SEL_BCOLOR);
			}
		}
	}
}

/*****************************************************************************
 Prototype    : win_gui_timerout_cb
 Description  : gui timerout callback
 Input        : struct timer_node_s * tn  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/24
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void win_gui_timerout_cb(struct timer_node_s * tn)
{
	add_timer(WIN_GUI_TIMEOUT, tn->handler);

	static uint32_t cnt = 0;
	static bool flag = true;
	if (m_value_flag)
	{
		cnt++;
		UG_COLOR fore_color = SELECT_ITEM_FCOLOR;
		UG_COLOR back_color = SELECT_ITEM_BCOLOR;
		if (cnt > WIN_SELECT_TIME)
		{
			cnt = 0;
			if (flag)
			{
				fore_color = SELECT_ITEM_FCOLOR;
				back_color = SELECT_ITEM_BCOLOR;
				flag = false;
			}else{
				fore_color = SET_ITEM_FCOLOR;
				back_color = SET_ITEM_BCOLOR;
				flag = true;
			}
			UG_TextboxSetForeColor(m_menu_select_list[m_menu_index].win, 
					m_menu_select_list[m_menu_index].id, fore_color);
			UG_TextboxSetBackColor(m_menu_select_list[m_menu_index].win, 
					m_menu_select_list[m_menu_index].id, back_color);
		}
	}else{
		cnt = 0;
	}

	if (m_menu_index == SUB_MENU_FACTORY)
	{
		static bool flag = false;
		if (btn_flash_cnt > 0)
			btn_flash_cnt--;
		else if (btn_flash_cnt == 0)
		{
			btn_flash_cnt = BTN_FLASH_DLY;
			if (!m_sud_menu_index){
				UG_ButtonSetBackColor(&win_tips, BTN_ID_0, (flag)?(BTN_SEL_BCOLOR):(BTN_NOT_SEL_BCOLOR));
				flag = (flag)?(false):(true);
			}else{
				UG_ButtonSetBackColor(&win_tips, BTN_ID_1, (flag)?(BTN_SEL_BCOLOR):(BTN_NOT_SEL_BCOLOR));
				flag = (flag)?(false):(true);
			}
		}

		if (factory_set_dly > 0)
		{
			factory_set_dly--;
			if (factory_set_dly == FACTORY_SET_TIME / 2)
				win_tips_update("Finish");
		}
		else if (factory_set_dly == 0)
		{
			factory_set_dly = -1;
			m_menu_index = MENU_FACTORY;
			UG_WindowHide(&win_tips);
		}
	}
	
	UG_Update();
}

/*****************************************************************************
 Prototype    : win_update_show
 Description  : windows update menu data show
 Input        : void  
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
void win_update_show(void)
{
	if (m_menu_index == MENU_MAIN) {
		win_main_update();
		return ;
	}
	win_menu1_update();
	win_menu2_update();
	win_sub_info_update();
}

/*****************************************************************************
 Prototype    : win_init
 Description  : windows init
 Input        : win_fun_t * fun  
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
void win_init(win_fun_t * fun)
{
	if (fun == NULL)
	{
		DEBUG_STR("win_init:fun==null");
		return ;
	}
	m_win_fun = *fun;

	m_value_flag = false;
	m_menu_index = MENU_MAIN;
	lcd_pwr_ctl(true);

	UG_Init(&m_gui, (void(*)(UG_S16,UG_S16,UG_COLOR))lcd_draw_point, LCD_X_PIXEL, LCD_Y_PIXEL);

   	UG_DriverRegister(DRIVER_FILL_FRAME, (void*)lcd_fill_frame);
   	UG_DriverRegister(DRIVER_DRAW_LINE, (void*)lcd_draw_line);
    UG_DriverEnable(DRIVER_DRAW_LINE);
   	UG_DriverEnable(DRIVER_FILL_FRAME);

	UG_FillScreen(C_BLACK);

	win_menu1_init();
	win_menu2_init();
	win_sub_info_init();
	win_tips_init();

	win_main_init();
	win_main_update();

	add_timer(WIN_GUI_TIMEOUT, win_gui_timerout_cb);
}


